﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LightPersist.Exceptions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestDomainModel;

namespace LightPersistTests
{
	[TestClass]
	public class Tests_object_reference_management : TripleTestsBase
	{

		/// <summary>
		/// Strong test for bug found bu general genetic test 'StressTest'
		/// </summary>
		[TestMethod]
		public void Should_work_in_complex_with_weak_backrefs_purging()
		{
			var child2 = child.Children.AddNew();
			tr.CommitTransaction();
			tr = Context.BeginTransaction();

			child = Context.GetObjectByID<FakeControl>(childID);
			child2 = Context.GetObjectByID<FakeControl>(child2.ID);

			child2.Children.AddNew();
			child.Children.Remove(child2);

			tr.Dispose();
			tr = Context.BeginTransaction();

			Reconnect();

			child = Context.GetObjectByID<FakeControl>(childID);
			child2 = Context.GetObjectByID<FakeControl>(child2.ID);

			child2.Children.AddNew();

			child.Children.Remove(child2);

		}

		[Serializable]
		public class MyNonModelReferenceType
		{
			public MyNonModelReferenceType()
			{

			}

			public MyNonModelReferenceType(string str)
			{
				Test = str;
			}

			public string Test { get; set; }

			public override string ToString()
			{
				return Test + " " + GetHashCode();
			}
		}

		[TestMethod]
		public void Should_not_allow_create_several_references_to_nonmodel_reference_type()
		{
			Assert.Inconclusive();

//			var a = new MyNonModelReferenceType("a");
//
//			mgr.SomeObject = a;
//			mgr.SomeObject2 = a;
//
//			Reconnect();
//
//			var obj = ((MyNonModelReferenceType)mgr.SomeObject);
//			obj.Test = "b";
//			mgr.SomeObject = obj;
//
//			obj = ((MyNonModelReferenceType)mgr.SomeObject2);
//			obj.Test = "c";
//			mgr.SomeObject2 = obj;
//
//			Reconnect();
//
//			Assert.AreEqual("b", ((MyNonModelReferenceType)mgr.SomeObject).Test);
//			Assert.AreEqual("c", ((MyNonModelReferenceType)mgr.SomeObject2).Test);
		}
		
		[TestMethod]
		public void Should_return_default_value_for_not_initialized_value_types()
		{
			var c = Context.Create<FakeControl>();
			Root.MainControl = c;
			Reconnect();
			Assert.AreEqual(0, Context.GetObjectByID<FakeControl>(c.ID).Width);
		}

		[TestMethod]
		public void Should_persist_object_references()
		{
			var main = Context.Create<FakeControl>();
			Root.MainControl = main;

			Reconnect();

			Assert.IsNotNull(Root.MainControl);
			Equal(main.ID, Root.MainControl.ID);
			Assert.IsNotNull(Context.GetObjectByID<FakeControl>(main.ID));

		}


		[TestMethod]
		public void Should_persist_object_references_from_null_and_to_null()
		{
			var main = Context.Create<FakeControl>();
			Root.MainControl = main;
			Root.MainControl = null;

			Reconnect();

			Assert.IsNull(Root.MainControl);
			Throws<StorageException>(delegate
			{
				Context.GetObjectByID<FakeControl>(main.ID);
			});
		}

		[TestMethod]
		public void Should_handle_replacement_of_object_reference()
		{
			var main = Context.Create<FakeControl>();
			var main2 = Context.Create<FakeControl>();
			Root.MainControl = main;
			Root.MainControl = main2;

			Reconnect();
			Assert.IsNotNull(Root.MainControl);

			Equal(main2.ID, Root.MainControl.ID);
			Assert.IsNotNull(Context.GetObjectByID<FakeControl>(main2.ID));
			Throws<StorageException>(delegate
			{
				Context.GetObjectByID<FakeControl>(main.ID);
			});
		}

		[TestMethod]
		public void Should_load_object_by_id_without_type()
		{
			Root.Name = "test1";
			Reconnect();
			var rootByID = Context.GetObjectByID(RootGuid);
			True(rootByID is FakeRoot);
			Equal("test1", ((FakeRoot)rootByID).Name);
			Equal(RootGuid, ((FakeRoot)rootByID).ID);

			var childByID = Context.GetObjectByID(childID);
			True(childByID is FakeControl);
			Equal("FIRST CHILD", ((FakeControl)childByID).Name);
			Equal(childID, ((FakeControl)childByID).ID);
		}

		[TestMethod]
		public void __Should_allow_to_create_2_level_of_objects()
		{

			Root.Children.Add(new FakeControl(Context));
			//Reconnect();
			Root.Children.Last().Children.Add(new FakeControl(Context));
			//Reconnect();

		}
	}
}
